package com.mlethe.library.multi.api;

import android.content.Context;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.mlethe.library.multi.api.listener.Callback;
import com.mlethe.library.multi.api.listener.OnActionCallback;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.modelpay.PayResp;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

/**
 * 微信回调处理类
 *
 * @Author Mlethe
 * @Date 2023/3/15
 */
final class WXEventHandler implements IWXAPIEventHandler {

    private static final String BASE_URL = "https://api.weixin.qq.com/sns/";

    private OnActionCallback mOnActionCallback;

    public WXEventHandler(OnActionCallback callback) {
        this.mOnActionCallback = callback;
    }

    @Override
    public void onReq(BaseReq baseReq) {
        switch (baseReq.getType()) {
            case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
                break;
            case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
                break;
            default:
                break;
        }
    }

    @Override
    public void onResp(BaseResp baseResp) {
        int type = baseResp.getType();
        MultiMedia media = MultiMedia.WECHAT;
        OnActionCallback callback = mOnActionCallback;
        mOnActionCallback = null;
        String state = null;
        if (callback != null) {
            state = callback.state;
        }
        if (state == null) {
            state = "";
        }
        String transaction = baseResp.transaction;
        MultiApi instance = MultiApi.getInstance();
        if (!state.equals(transaction)) {
            if (callback != null) {
                Context context = instance.getContext();
                callback.onFailure(media, -8006, context.getString(R.string.multi_api_not_inconsistent_requests));
            }
            return;
        }
        int errCode = baseResp.errCode;
        instance.i("WECHAT handler onComplete. type->" + type + ", code=" + errCode);
        if (type == ConstantsAPI.COMMAND_SENDAUTH) {
            // 授权登录
            switch (errCode) {
                case BaseResp.ErrCode.ERR_OK:
                    // 授权成功
                    SendAuth.Resp sendResp = (SendAuth.Resp) baseResp;
                    getAccessToken(sendResp, callback);
                    break;
                case BaseResp.ErrCode.ERR_USER_CANCEL:
                    // 授权取消
                    if (callback != null) {
                        callback.onCancel(media);
                    }
                    break;
                case BaseResp.ErrCode.ERR_AUTH_DENIED:
                    // 权限验证失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                case BaseResp.ErrCode.ERR_SENT_FAILED:
                    // 授权失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                default:
                    // 未知错误
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
            }
        } else if (type == ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX) {
            // 分享
            switch (errCode) {
                case BaseResp.ErrCode.ERR_OK:
                    // 分享成功
                    Map<String, String> map = new HashMap<>();
                    if (callback != null) {
                        callback.onComplete(media, map);
                    }
                    break;
                case BaseResp.ErrCode.ERR_USER_CANCEL:
                    // 分享取消
                    if (callback != null) {
                        callback.onCancel(media);
                    }
                    break;
                case BaseResp.ErrCode.ERR_AUTH_DENIED:
                    // 权限验证失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                case BaseResp.ErrCode.ERR_SENT_FAILED:
                    // 分享失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                default:
                    // 未知错误
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
            }
        } else if (type == ConstantsAPI.COMMAND_PAY_BY_WX) {
            // 支付
            switch (errCode) {
                case BaseResp.ErrCode.ERR_OK:
                    // 支付成功
                    instance.i("WECHAT pay success.");
                    PayResp payResp = (PayResp) baseResp;
                    Map<String, String> map = new HashMap<>();
                    map.put("extData", payResp.extData);
                    map.put("openId", payResp.openId);
                    map.put("returnKey", payResp.returnKey);
                    map.put("prepayId", payResp.prepayId);
                    if (callback != null) {
                        callback.onComplete(media, map);
                    }
                    break;
                case BaseResp.ErrCode.ERR_USER_CANCEL:
                    // 支付取消
                    if (callback != null) {
                        callback.onCancel(media);
                    }
                    break;
                case BaseResp.ErrCode.ERR_AUTH_DENIED:
                    // 权限验证失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                case BaseResp.ErrCode.ERR_SENT_FAILED:
                    // 支付失败
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
                default:
                    // 未知错误
                    if (callback != null) {
                        callback.onFailure(media, errCode, baseResp.errStr);
                    }
                    break;
            }
        }
    }

    /**
     * 第二步：通过 code 获取 access_token
     *
     * @param sendResp
     */
    private void getAccessToken(SendAuth.Resp sendResp, OnActionCallback callback) {
        MultiApi instance = MultiApi.getInstance();
        Platform platForm = instance.getPlatForm(MultiMedia.WECHAT);
        String url = BASE_URL + "oauth2/access_token?appid=" + platForm.getAppId() + "&secret=" + platForm.getAppSecret() + "&code=" + sendResp.code + "&grant_type=authorization_code";
        instance.i("WECHAT getAccessToken start request.");
        boolean status = instance.request(url, new Callback<JSONObject>() {
            @Override
            public void onSuccess(@NonNull JSONObject jsonObject) {
                instance.i("WECHAT getAccessToken success response. data=" + jsonObject);
                if (!jsonObject.has("errcode")) {
                    String token = jsonObject.optString("access_token");
                    String refreshToken = jsonObject.optString("refresh_token");
                    String openid = jsonObject.optString("openid");
                    String unionid = jsonObject.optString("unionid");
                    int expiration = jsonObject.optInt("expires_in");
                    if (callback != null && !callback.isGetUserInfo) {
                        Map<String, String> map = new HashMap<>();
                        map.put("openid", openid);
                        map.put("unionid", unionid);
                        map.put("accessToken", token);
                        map.put("refreshToken", refreshToken);
                        map.put("expiration", expiration + "");
                        callback.onComplete(MultiMedia.WECHAT, map);
                        return;
                    }
                    getUserInfo(token, refreshToken, openid, expiration, sendResp.lang, callback);
                } else {
                    int errCode = -9001;
                    String errMsg = "";
                    try {
                        errCode = jsonObject.getInt("errcode");
                        errMsg = jsonObject.getString("errmsg");
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                    if (TextUtils.isEmpty(errMsg)) {
                        Context context = instance.getContext();
                        errMsg = context.getString(R.string.multi_api_obtain_user_information_fail);
                    }
                    if (callback != null) {
                        callback.onFailure(MultiMedia.WECHAT, errCode, errMsg);
                    }
                }

            }

            @Override
            public void onFailure(int code, @NonNull String msg) {
                instance.e("WECHAT getAccessToken fail response. code=" + code + ", message=" + msg);
                if (callback != null) {
                    callback.onFailure(MultiMedia.WECHAT, code, msg);
                }
            }
        });
        if (!status) {
            if (callback != null) {
                Context context = MultiApi.getInstance().getContext();
                callback.onFailure(MultiMedia.WECHAT, -8007, context.getString(R.string.multi_api_request_initiation_failed));
            }
        }
    }

    /**
     * 获取用户信息
     *
     * @param accessToken
     * @param openid
     */
    private void getUserInfo(String accessToken, String refreshToken, String openid, int expiration, String lang, OnActionCallback callback) {
        MultiApi instance = MultiApi.getInstance();
        String url = BASE_URL + "userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=" + lang;
        instance.i("WECHAT getUserinfo start request.");
        boolean status = instance.request(url, new Callback<JSONObject>() {
            /**
             * openid	普通用户的标识，对当前开发者账号唯一
             * nickname	普通用户昵称
             * sex	普通用户性别，1 为男性，2 为女性
             * province	普通用户个人资料填写的省份
             * city	普通用户个人资料填写的城市
             * country	国家，如中国为 CN
             * headimgurl	用户头像，最后一个数值代表正方形头像大小（有 0、46、64、96、132 数值可选，0 代表 640*640 正方形头像），用户没有头像时该项为空
             * privilege	用户特权信息，json 数组，如微信沃卡用户为（chinaunicom）
             * unionid	用户统一标识。针对一个微信开放平台账号下的应用，同一用户的 unionid 是唯一的。
             *
             * @param jsonObject
             */
            @Override
            public void onSuccess(@NonNull JSONObject jsonObject) {
                instance.i("WECHAT getUserinfo success response. data=" + jsonObject);
                Map<String, String> map = new HashMap<>();
                map.put("openid", jsonObject.optString("openid"));
                map.put("unionid", jsonObject.optString("unionid"));
                map.put("accessToken", accessToken);
                map.put("refreshToken", refreshToken);
                map.put("expiration", expiration + "");
                map.put("nickname", jsonObject.optString("nickname"));
                map.put("iconUrl", jsonObject.optString("headimgurl"));
                map.put("sex", jsonObject.optString("sex"));
                map.put("country", jsonObject.optString("country"));
                map.put("province", jsonObject.optString("province"));
                map.put("city", jsonObject.optString("city"));
                map.put("privilege", jsonObject.optString("privilege"));
                if (callback != null) {
                    callback.onComplete(MultiMedia.WECHAT, map);
                }
            }

            @Override
            public void onFailure(int code, @NonNull String msg) {
                instance.e("WECHAT getUserinfo fail response. code=" + code + ", message=" + msg);
                if (callback != null) {
                    callback.onFailure(MultiMedia.WECHAT, code, msg);
                }
            }
        });
        if (!status) {
            if (callback != null) {
                Context context = MultiApi.getInstance().getContext();
                callback.onFailure(MultiMedia.WECHAT, -8007, context.getString(R.string.multi_api_request_initiation_failed));
            }
        }
    }
}
